package org.ws.task.listener;

import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.ws.task.listener.item.ItemCommitListener;
import org.ws.task.listener.item.ItemFetchListener;
import org.ws.task.listener.item.ItemProcessListener;
import org.ws.task.listener.item.ItemPushListener;
import org.ws.task.listener.item.TaskItemListener;
import org.ws.task.model.*;
import org.ws.task.model.protocol.CommitRequest;
import org.ws.task.model.protocol.CommitResponse;
import org.ws.task.model.protocol.PullItemRequest;
import org.ws.task.model.protocol.PullItemResponse;
import org.ws.task.model.protocol.PushItemRequest;
import org.ws.task.model.protocol.PushItemResponse;

import java.util.List;

public class TaskItemListenerManager implements RegisterListener<TaskItemListener>, ItemFetchListener, ItemProcessListener, ItemCommitListener, ItemPushListener {

    private static Logger log = LoggerFactory.getLogger(TaskItemListenerManager.class.getName());

    private final List<ItemFetchListener> requestListeners;
    private final List<ItemProcessListener> processListeners;
    private final List<ItemCommitListener> commitListeners;
    private final List<ItemPushListener> pushListeners;

    public TaskItemListenerManager() {
        this.requestListeners = Lists.newLinkedList();
        this.processListeners = Lists.newLinkedList();
        this.commitListeners = Lists.newLinkedList();
        this.pushListeners = Lists.newLinkedList();
    }

    @Override
    public void registerListener(TaskItemListener listener){
        boolean matched = false;
        if(listener instanceof ItemFetchListener){
            requestListeners.add((ItemFetchListener) listener);
            matched = true;
        }
        if(listener instanceof ItemProcessListener){
            processListeners.add((ItemProcessListener) listener);
            matched = true;
        }
        if(listener instanceof ItemCommitListener){
            commitListeners.add((ItemCommitListener) listener);
            matched = true;
        }
        if(listener instanceof ItemPushListener){
            pushListeners.add((ItemPushListener) listener);
            matched = true;
        }
        if(!matched) {
            log.warn("listener:[{}] can not match.",listener.getClass().getName());
        }
    }

    @Override
    public void beforeCommit(final CommitRequest request) {
        this.commitListeners.forEach(l->l.beforeCommit(request));
    }

    @Override
    public void afterCommit(final CommitRequest request,final CommitResponse response) {
        this.commitListeners.forEach(l->l.afterCommit(request,response));
    }

    @Override
    public void onCommonError(final CommitRequest request,final  Throwable e) {
        this.commitListeners.forEach(l->l.onCommonError(request,e));
    }

    @Override
    public void beforeProcess(final List<TaskItem> items) {
        this.processListeners.forEach(l->l.beforeProcess(items));
    }

    @Override
    public void afterProcess(final List<TaskItem> items) {
        this.processListeners.forEach(l->l.afterProcess(items));
    }

    @Override
    public void onProcessError(final List<TaskItem> items, final Throwable e) {
        this.processListeners.forEach(l->l.onProcessError(items,e));
    }

    @Override
    public void beforeFetch(final PullItemRequest request) {
        this.requestListeners.forEach(l->l.beforeFetch(request));
    }

    @Override
    public void afterFetch(final PullItemRequest request, final PullItemResponse response) {
        this.requestListeners.forEach(l->l.afterFetch(request,response));
    }

    @Override
    public void onFetchError(final PullItemRequest request, final  Throwable e) {
        this.requestListeners.forEach(l->l.onFetchError(request,e));
    }

    @Override
    public void beforePush(final PushItemRequest request) {
        this.pushListeners.forEach(l->l.beforePush(request));
    }

    @Override
    public void afterPush(PushItemRequest request, PushItemResponse response) {
        this.pushListeners.forEach(l->l.afterPush(request,response));
    }

    @Override
    public void onPushError(PushItemRequest request, Throwable e) {
        this.pushListeners.forEach(l->l.onPushError(request,e));
    }
}
